package org.flowers.unbeaten.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.flowers.unbeaten.base.constant.Constants;
import org.flowers.unbeaten.base.entity.User;
import org.flowers.unbeaten.base.service.IBaseService;
import org.flowers.unbeaten.config.proprety.CustomerRedisProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * @description Http会话工具类
 * @author RyanWang
 * @date 2021-08-03 10:23:42
 * @version 1.0
 */
@Service
public class HttpSessionUtils {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private CustomerRedisProperty customerRedisProperty;

    @Autowired
    private IBaseService baseService;

    /**
     * 创建token
     * @param user
     * @param roles
     * @param permissions
     * @return
     */
    public String createTokenAndUser(User user, List<String> roles, Set<String> permissions) {
        // 方便根据id找到redis的key， 修改密码/退出登陆方便使用
        String token = Token.createRandomToken(128, false) + "#" + user.getUserId();
        JSONObject sessionInfo = new JSONObject();
        sessionInfo.put(Constants.USER_ID_KEY, user.getUserId());
        sessionInfo.put(Constants.USER_NAME_KEY, user.getUsername());
        sessionInfo.put(Constants.ROLES_KEY, roles);
        sessionInfo.put(Constants.PERMISSIONS_KEY, permissions);
        String key = customerRedisProperty.getUserTokenPrefix() + token;
        // 设置该用户已登录的token
        redisTemplate.opsForValue().set(key, sessionInfo.toJSONString(), customerRedisProperty.getUserTokenExpire());
        // 登陆后删除权限刷新标志
        redisTemplate.delete(customerRedisProperty.getPermissionRefreshPrefix() + user.getUserId());
        return token;
    }

    /**
     * 根据token获取userId
     * @param token
     * @return
     */
    public String getUserIdByToken(String token) {
        if (StringUtils.isBlank(token) || !token.contains("#")) {
            return "";
        } else {
            return token.substring(token.indexOf("#") + 1);
        }
    }

    /**
     * 获取参数中的token
     * @return
     */
    public String getTokenFromHeader() {
        String token = ServletUtils.getRequest().getHeader(Constants.ACCESS_TOKEN);
        // 如果header中不存在token，则从参数中获取token
        if (StringUtils.isBlank(token)) {
            token = ServletUtils.getRequest().getParameter(Constants.ACCESS_TOKEN);
        }
        return token;
    }

    /**
     * 获取当前session信息
     * @return
     */
    public JSONObject getCurrentSession() {
        String token = getTokenFromHeader();
        if (Objects.nonNull(token)) {
            if (redisTemplate.hasKey(customerRedisProperty.getUserTokenPrefix() + token)) {
                String sessionInfoStr = redisTemplate.opsForValue().get(customerRedisProperty.getUserTokenPrefix() + token);
                return JSON.parseObject(sessionInfoStr);
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 获取当前session信息 username
     * @return
     */
    public String getCurrentUsername() {
        if (Objects.nonNull(getCurrentSession())) {
            return getCurrentSession().getString(Constants.USER_NAME_KEY);
        } else {
            return null;
        }
    }

    /**
     * 获取当前session信息 UserId
     * @return UserId
     */
    public String getCurrentUserId() {
        if (Objects.nonNull(getCurrentSession())) {
            return getCurrentSession().getString(Constants.USER_ID_KEY);
        } else {
            return null;
        }
    }

    /**
     * 使当前用户的token失效
     */
    public void abortCurrentUserByToken() {
        String token = getTokenFromHeader();
        redisTemplate.delete(customerRedisProperty.getUserTokenPrefix() + token);
    }

    /**
     * 使所有用户的token失效
     */
    public void abortAllUserByToken() {
        String token = getTokenFromHeader();
        String userId = getUserIdByToken(token);
        redisTemplate.delete(customerRedisProperty.getUserTokenPrefix() + "*#" + userId);
    }

    /**
     * 使用户的token失效
     */
    public void abortUserByUserId(String userId) {
        redisTemplate.delete(customerRedisProperty.getUserTokenPrefix() + "*#" + userId);
    }

    /**
     * 使多个用户的token失效
     */
    public void abortUserByUserIds(List<String> userIds) {
        if (CollectionUtils.isNotEmpty(userIds)) {
            for (String id : userIds) {
                redisTemplate.delete(customerRedisProperty.getUserTokenPrefix() + "*#" + id);
            }
        }
    }

    /**
     * 根据用户id， 刷新redis用户权限
     * @param userId
     */
    public void refreshUerId(String userId) {
        redisTemplate.delete(customerRedisProperty.getUserTokenPrefix() + "*#" + userId);
        Set<String> keys = redisTemplate.keys("#" + userId);
        // 如果修改了角色/权限， 那么刷新权限
        for (String key : keys) {
            JSONObject redisSession = JSON.parseObject(redisTemplate.opsForValue().get(key));
            List<String> roleNames = getRolesByUserId(userId);
            if (!CollectionUtils.isEmpty(roleNames)) {
                redisSession.put(Constants.ROLES_KEY, roleNames);
            }
            Set<String> permissions = getPermissionsByUserId(userId);
            redisSession.put(Constants.PERMISSIONS_KEY, permissions);
            Long redisTokenKeyExpire = redisTemplate.getExpire(key);
            // 刷新token绑定的角色权限
            redisTemplate.opsForValue().set(key, redisSession.toJSONString(), redisTokenKeyExpire);

        }
    }

    /**
     * 根据角色id刷新redis用户权限
     * @param roleId
     */
    public void refreshRolePermission(String roleId) {
        List<String> userIds = baseService.selectUserIdsByRoleId(roleId);
        if (!CollectionUtils.isEmpty(userIds)) {
            userIds.parallelStream().forEach(this::refreshUerId);
        }
    }

    /**
     * 根据menuId刷新redis用户权限
     * @param menuId
     */
    public void refreshPermission(String menuId) {
        List<String> userIds = baseService.selectUserIdsByMenuId(menuId);
        if (!CollectionUtils.isEmpty(userIds)) {
            userIds.parallelStream().forEach(this::refreshUerId);
        }
    }

    private List<String> getRolesByUserId(String userId) {
        return baseService.selectRoleNames(userId);
    }

    private Set<String> getPermissionsByUserId(String userId) {
        return baseService.selectPermissionsByUserId(userId);
    }

}
